package com.learning.demos;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 *  * 共享锁 指该锁可被多个线程所持有，对ReentrantReadWriteLock其读锁是共享锁，其写锁是独占锁；读锁的共享锁可办证并发读是非常高效的，读写，写读，
 *  * 写写的过程都是互斥的(不能共存)。
 *
 *  写操作：原子+独占 整个过程必须是一个完整的统一体，中间不许被打断
 *
 *
 *  加锁之后执行效果
 *  1	 writing1
 * 1	 write done
 * 0	 writing0
 * 0	 write done
 * 2	 writing2
 * 2	 write done
 * 3	 writing3
 * 3	 write done
 * 4	 writing4
 * 4	 write done
 * 0	 reading0
 * 1	 reading1
 * 2	 reading2
 * 3	 reading3
 * 4	 reading4
 * 2	 read done2
 * 4	 read done4
 * 1	 read done1
 * 0	 read done0
 * 3	 read done3
 *
 *  java.util.concurrent  juc
 * @author adolphw
 */
public class ReadWriteLockDemo {

    public static void main(String[] args) {

        MyCache myCache = new MyCache();

        for (int i = 0; i < 5; i++) {
            final int tmpInt = i;
            new Thread(() -> {
                myCache.put(tmpInt + "", tmpInt + "");
            }, String.valueOf(tmpInt)).start();
        }

        for (int i = 0; i < 5; i++) {
            final int tmpInt = i;
            new Thread(() -> {
                myCache.get(tmpInt + "");
            }, String.valueOf(tmpInt)).start();
        }
    }

}


class MyCache {
    private volatile Map<String, Object> map = new HashMap<>();
    // private Lock lock = new ReentrantLock();
    private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    public void put(String key, Object value) {
        readWriteLock.writeLock().lock();

        try {
            System.out.println(Thread.currentThread().getName() + "\t writing" + key);
            TimeUnit.MILLISECONDS.sleep(300);
            map.put(key, value);
            System.out.println(Thread.currentThread().getName() + "\t write done");
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            readWriteLock.writeLock().unlock();
        }
    }

    public void get(String key) {

        readWriteLock.readLock().lock();

        try {
            System.out.println(Thread.currentThread().getName() + "\t reading" + key);

            TimeUnit.MILLISECONDS.sleep(300);
            Object result = map.get(key);
            System.out.println(Thread.currentThread().getName() + "\t read done" + result);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            readWriteLock.readLock().unlock();
        }
    }

    public void clearMap() {
        map.clear();
    }
}